using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;


using System.IO;
using System.Windows.Forms;
using BrickBreaker.Core;



namespace LevelEditor
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;


        #region DATA_MEMBERS_PRIVATE/GLOBAL
        //class Vars...
        private IntPtr drawSurface;
        private Form parentForm;
        private PictureBox pictureBox;
        private Control gameForm;
        #endregion;


        #region XNA_WIN-FORM_SHARED_DATA
        //
        public List<Brick> bricks;
        public MouseState oldMouseState;
        public Texture2D brickTexture;
        
        //public flags to trigger Update/Draw
        public bool drawBG = false;
        public bool drawGrid = false;
        public Vector2 trackMouseXY = new Vector2();
        public bool clickedOutsideGrid = false;
        public string displayMsg = "";

        //Add/Remove Brick, using Mouse
        public Vector2 rightClickLocation = new Vector2();
        public Vector2 leftClickLocation = new Vector2();
        //public Vector2 removeByLClick = new Vector2();

        public bool addByRightClick = false;
        public bool addByLeftClick = false;
        public bool removeByRightClick = false;
        public bool removeByLeftClick = false;
        public Brick tempBrick;

        //Actual vars doing Work
        private Texture2D background;
        private Texture2D grid;

        //Brick Textures...
        private Texture2D blue, green, grey, orange, red;

        //Track level changes were saved
        public bool levelSaved = true;
        public string unsaved = "";

        //locally used vars
        SpriteFont debugFont;
        SpriteFont debugBrickFont;
        #endregion


        #region OLD_CONSTRUCTOR
        //public Game1()
        //{
        //    graphics = new GraphicsDeviceManager(this);
        //    Content.RootDirectory = "Content";
        //} 
        #endregion


        //New Constructor
        public Game1(IntPtr drawSurface, Form parentForm, PictureBox surfacePictureBox)
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            bricks = new List<Brick>();


            #region INSTANTIATE_EVENT-HANDLERS
            //data member assignment....
            this.drawSurface = drawSurface;
            this.parentForm = parentForm;
            this.pictureBox = surfacePictureBox;

            //instantiating event handlers....
            graphics.PreparingDeviceSettings += new EventHandler<PreparingDeviceSettingsEventArgs>(graphics_PreparingDeviceSettings);
            Mouse.WindowHandle = drawSurface;
            gameForm = System.Windows.Forms.Control.FromHandle(this.Window.Handle);
            gameForm.VisibleChanged += new EventHandler(gameForm_VisibleChanged);
            gameForm.SizeChanged += new EventHandler(pictureBox_SizeChanged);
            //
            #endregion INSTANTIATE_EVENT-HANDLERS
        }

        #region EVENT_HANDLERS
        //Event Handlers
        //Add the graphics_PreparingDeviceSettings() event handler to the Game1 class:
        void graphics_PreparingDeviceSettings(object sender, PreparingDeviceSettingsEventArgs e)
        {
            e.GraphicsDeviceInformation.PresentationParameters.
            DeviceWindowHandle = drawSurface;
        }

        //Event Handler, when GameForm visibility changes
        private void gameForm_VisibleChanged(object sender, EventArgs e)
        {
            if (gameForm.Visible == true)
                gameForm.Visible = false;
        }

        //Event Handler, when PictureBox Size changes
        void pictureBox_SizeChanged(object sender, EventArgs e)
        {
            if (parentForm.WindowState != System.Windows.Forms.FormWindowState.Minimized)
            {
                graphics.PreferredBackBufferWidth = pictureBox.Width;
                graphics.PreferredBackBufferHeight = pictureBox.Height;
                graphics.ApplyChanges();
            }
        }
        #endregion EVENT_HANDLERS

        
        protected override void Initialize()
        {
            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);


            #region ASSIGN_TEXTURES
            background = Content.Load<Texture2D>(@"BG\background_yellow");
            grid = Content.Load<Texture2D>(@"BG\background_grid"); 

            //load brick textures...
            blue = Content.Load<Texture2D>(@"Bricks\brick_blue");
            green = Content.Load<Texture2D>(@"Bricks\brick_green");
            grey = Content.Load<Texture2D>(@"Bricks\brick_grey");
            orange = Content.Load<Texture2D>(@"Bricks\brick_orange");
            red = Content.Load<Texture2D>(@"Bricks\brick_red");

            //load fonts...
            debugFont = Content.Load<SpriteFont>(@"Fonts\debugFont");
            debugBrickFont = Content.Load<SpriteFont>(@"Fonts\brickFont");
            #endregion
        }

        
        protected override void UnloadContent()
        {
            //do something...
        }

        
        protected override void Update(GameTime gameTime)
        {
            MouseState ms = Mouse.GetState();

            if ((ms.X >= 0) && (ms.Y >= 0) &&
                (ms.X <= this.pictureBox.Width) && (ms.Y <= this.pictureBox.Height)
                )
            {
                this.trackMouseXY = new Vector2(ms.X, ms.Y);
            }

            #region ADD_BRICK_TO_BRID
            //Add a Brick to Grid
            if (addByRightClick)
            {
                AddBrick_OnRightOrLeftClick(tempBrick);
                addByRightClick = false;
            }

            //Add a Brick to Grid
            if (addByLeftClick)
            {
                AddBrick_OnRightOrLeftClick(tempBrick);
                addByLeftClick = false;
            }

            //Remove a Brick from Grid
            if (removeByRightClick)
            {
                RemoveBrick_OnRightOrLeftClick();
                //level has been changed...
                this.levelSaved = false;

                removeByRightClick = false;
            } 
            #endregion

            //Remove a Brick from Grid
            if (removeByLeftClick)
            {
                RemoveBrick_OnRightOrLeftClick();
                //level has been changed...
                this.levelSaved = false;

                removeByLeftClick = false;
            }

            //Track if Level has unsaved changes
            //if (!this.levelSaved)
            //{
            //    this.unsaved = "Unsaved Changes!";
            //}


            oldMouseState = ms;

            base.Update(gameTime);
        }
        
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            spriteBatch.Begin();

            if (drawBG) { spriteBatch.Draw(background, Vector2.Zero, Color.White);
            }
            if (drawGrid) { spriteBatch.Draw(grid, Vector2.Zero, Color.White);
            }

            foreach (Brick brick in bricks) 
            { 
                brick.Draw(spriteBatch);
                spriteBatch.DrawString(debugBrickFont, brick.Position.ToString(), new Vector2(brick.Position.X + 5, brick.Position.Y + 5), Color.Black);
            }

            DebugMsg(spriteBatch);

            spriteBatch.End();

            base.Draw(gameTime);
        }


        #region CUSTOM_EVENT_HANDLING_METHODS

        //switch brick texture
        public void SwapBrickTexture(BrickType type)
        {
            switch (type)
            {
                case BrickType.RED:
                    this.brickTexture = red;
                    break;
                case BrickType.BLUE:
                    this.brickTexture = blue;
                    break;
                case BrickType.GREEN:
                    this.brickTexture = green;
                    break;
                case BrickType.ORANGE:
                    this.brickTexture = orange;
                    break;
                case BrickType.GREY:
                    this.brickTexture = grey;
                    break;
               }
        }

        public void AddBrick_OnRightOrLeftClick(Brick brick)
        {
            Vector2 mouseClick = new Vector2();
            int i = -1;

            if (addByRightClick) { mouseClick = rightClickLocation;
            }
            else if (addByLeftClick) { mouseClick = leftClickLocation;
            }

            if (bricks.Count != 0)
            {
                foreach (Brick b in bricks)
                {
                    //Remove if cell is filled
                    if (b.Position == ConvertMouseClickToGridLocation(mouseClick))
                    {
                        i = bricks.IndexOf(b);
                        bricks.RemoveAt(i);
                        this.displayMsg = "Replaced Cell with New brick";
                        break;
                    }
                }//foreach
                if (i < 0) { this.displayMsg = "Added brick to cell";
                }
            }
            else { this.displayMsg = "Added brick to cell"; }
            
            brick.Position = ConvertMouseClickToGridLocation(mouseClick);
            bricks.Add(brick);
        }

        public void RemoveBrick_OnRightOrLeftClick()//(Brick brick)
        {
            Vector2 mouseClick = new Vector2();
            int i = -1;

            this.displayMsg = "";

            if (removeByRightClick) { mouseClick = rightClickLocation;
            }
            else if (removeByLeftClick)
            {
                mouseClick = leftClickLocation;//doubleClickLocation;
            }
            
            if (bricks.Count != 0)
            {
                foreach (Brick b in bricks)
                {
                    if (b.Position == ConvertMouseClickToGridLocation(mouseClick))
                    {
                        i = bricks.IndexOf(b); 
                        this.displayMsg = "Removed brick from cell";
                        break;
                    }
                }//foreach
                if (i > -1) 
                { 
                    bricks.RemoveAt(i);

                    //level has been changed...
                    this.levelSaved = false;
                }
                else { this.displayMsg = "Cell is Empty, nothing to delete";
                }
            }
            else { displayMsg = "No items to remove, Grid Empty!"; }
        }

        private Vector2 ConvertMouseClickToGridLocation(Vector2 pos)
        {
            float minX = 0, maxX = 0, minY = 0, maxY = 0;
            int rows = 12, cols = 10, myRow = 0, myCol = 0;

            for (int i = 1; i <= rows; i++)
            {
                minX = 100 + ((i - 1) * 50);
                maxX = 100 + (((i + 1) - 1) * 50);

                if (pos.X >= minX && pos.X < maxX)
                {
                    myRow = i;
                    break;
                }
            }

            for (int i = 1; i <= cols; i++)
            {
                minY = 100 + ((i - 1) * 30);
                maxY = 100 + (((i + 1) - 1) * 30);

                if (pos.Y >= minY && pos.Y < maxY)
                {
                    myCol = i;
                    break;
                }
            }

            Vector2 v = new Vector2();
            v.X = 100 + ((myRow - 1) * 50);
            v.Y = 100 + ((myCol - 1) * 30);

            return v;
        }


        //Debug Messages
        private void DebugMsg(SpriteBatch spriteBatch)
        {
            spriteBatch.DrawString(debugFont, "Mouse: " + trackMouseXY.X + ", " + trackMouseXY.Y, Vector2.Zero, Color.LightBlue);
            spriteBatch.DrawString(debugFont, "Mouse L-Click: " + leftClickLocation.X + ", " + leftClickLocation.Y, new Vector2(0, 555), Color.LightBlue);
            spriteBatch.DrawString(debugFont, "Mouse R-Click: " + rightClickLocation.X + ", " + rightClickLocation.Y, new Vector2(0, 570), Color.LightBlue);
            spriteBatch.DrawString(debugFont, "Bricks Count: " + bricks.Count, new Vector2(0, 585), Color.LightBlue);
            spriteBatch.DrawString(debugFont, displayMsg, new Vector2(300, 0), Color.PowderBlue);
            spriteBatch.DrawString(debugFont, unsaved, new Vector2(300, 15), Color.Plum);
        }
        #endregion CUSTOM_EVENT_HANDLING_METHODS
    }//class
}//namespace